﻿namespace Pub.Class
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;

    public static class IEnumerableExtensions
    {
        public static ReadOnlyCollection<T> AsReadOnly<T>(this IEnumerable<T> @this)
        {
            return new ReadOnlyCollection<T>(new List<T>(@this));
        }

        public static IEnumerable<TSource> Concat<TSource>(this IEnumerator<TSource> left, IEnumerator<TSource> right)
        {
        Label_PostSwitchInIterator:;
            if (left.MoveNext())
            {
                yield return left.Current;
                goto Label_PostSwitchInIterator;
            }
            while (right.MoveNext())
            {
                yield return right.Current;
            }
        }

        public static IEnumerable<TSource> Concat<TSource>(this IEnumerator<TSource> left, TSource last)
        {
        Label_PostSwitchInIterator:;
            if (left.MoveNext())
            {
                yield return left.Current;
                goto Label_PostSwitchInIterator;
            }
            yield return last;
        }

        public static IEnumerable<TOutput> ConvertAll<TInput, TOutput>(this IEnumerable<TInput> coll, Converter<TInput, TOutput> converter)
        {
            return (from input in coll select converter(input));
        }

        public static TResult ConvertFirstSpecification<TObject, TResult>(this IEnumerable<TObject> source, Func<TObject, TResult> converter, Predicate<TObject> predicate)
        {
            TObject local = source.FindFirstSpecification<TObject>(predicate);
            if (local.IsNull())
            {
                return default(TResult);
            }
            return converter(local);
        }

        public static IEnumerable<TTarget> ConvertTo<TSource, TTarget>(this IEnumerable<TSource> source)
        {
            foreach (TSource iteratorVariable0 in source)
            {
                yield return iteratorVariable0.ConvertTo<TTarget>();
            }
        }

        public static IList<TObject> CopyAllToList<TObject>(this IEnumerable<TObject> source)
        {
            IList<TObject> copy = new List<TObject>();
            copy.ForEach<TObject>(delegate (TObject t) {
                copy.Add(t);
            });
            return copy;
        }

        public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)
        {
            return source.GroupBy<T, V>(keySelector).Select<IEnumerable<IGrouping<V, T>>, IGrouping<V, T>>(g => g.FirstOrDefault<IGrouping<V, T>>());
        }

        public static IQueryable<T> Distinct<T, V>(this IQueryable<T> source, Expression<Func<T, V>> keySelector)
        {
            return source.GroupBy<T, V>(keySelector).Select<IQueryable<IGrouping<V, T>>, IGrouping<V, T>>(g => g.FirstOrDefault<IGrouping<V, T>>()).AsQueryable<T>();
        }

        public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer)
        {
            return source.GroupBy<T, V>(keySelector, comparer).Select<IEnumerable<IGrouping<V, T>>, IGrouping<V, T>>(g => g.FirstOrDefault<IGrouping<V, T>>());
        }

        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
        {
            foreach (TSource local in source)
            {
                action(local);
            }
            return source;
        }

        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource, int> action)
        {
            int num = 0;
            foreach (TSource local in source)
            {
                action(local, num++);
            }
            return source;
        }

        public static IEnumerable Do(this IEnumerable source, Action<object> action)
        {
            foreach (object obj2 in source)
            {
                action(obj2);
            }
            return source;
        }

        public static IEnumerable Do(this IEnumerable source, Action<object, int> action)
        {
            int num = 0;
            foreach (object obj2 in source)
            {
                action(obj2, num++);
            }
            return source;
        }

        public static bool Exist<T>(this IEnumerable<T> coll, Predicate<T> predicate)
        {
            IEnumerator<T> enumerator = coll.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if (predicate(enumerator.Current))
                {
                    return true;
                }
            }
            return false;
        }

        public static TObject FindFirstSpecification<TObject>(this IEnumerable<TObject> source, Predicate<TObject> predicate)
        {
            foreach (TObject local in source)
            {
                if (predicate(local))
                {
                    return local;
                }
            }
            return default(TObject);
        }

        public static IEnumerable<T> Flatten<T>(this IEnumerable<T> inputs, Func<T, IEnumerable<T>> enumerate)
        {
            if (!inputs.IsNotNull())
            {
                goto Label_0103;
            }
            Stack<T> iteratorVariable0 = new Stack<T>(inputs);
        Label_PostSwitchInIterator:;
            while (iteratorVariable0.Count > 0)
            {
                T iteratorVariable1 = iteratorVariable0.Pop();
                if (!iteratorVariable1.IsNull())
                {
                    yield return iteratorVariable1;
                    IEnumerable<T> iteratorVariable2 = enumerate.IsNotNull() ? enumerate(iteratorVariable1) : null;
                    if (iteratorVariable2.IsNotNull())
                    {
                        foreach (T local in iteratorVariable2)
                        {
                            iteratorVariable0.Push(local);
                        }
                    }
                    goto Label_PostSwitchInIterator;
                }
            }
        Label_0103:;
        }

        public static IEnumerable Flatten(this IEnumerable inputs, Func<object, IEnumerable> enumerate)
        {
            return inputs.Cast<object>().Flatten<object>(o => (enumerate(o) ?? new object[0]).Cast<object>());
        }

        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (T iteratorVariable0 in source)
            {
                action(iteratorVariable0);
                yield return iteratorVariable0;
            }
        }

        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T, int> action)
        {
            int iteratorVariable0 = 0;
            foreach (T iteratorVariable1 in source)
            {
                action(iteratorVariable1, iteratorVariable0);
                iteratorVariable0++;
                yield return iteratorVariable1;
            }
        }

        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> items, Action<T> odd, Action<T> even)
        {
            bool isOdd = true;
            return items.ForEach<T>(delegate (T item) {
                if (isOdd)
                {
                    odd(item);
                }
                else
                {
                    even(item);
                }
                isOdd = !isOdd;
            });
        }

        public static IEnumerable<T[]> GroupEvery<T>(this IEnumerable<T> enumeration, int count)
        {
            if (enumeration.IsNull())
            {
                throw new ArgumentNullException("enumeration不能为null");
            }
            if (count <= 0)
            {
                throw new ArgumentOutOfRangeException("count不能小于0");
            }
            int iteratorVariable0 = 0;
            T[] iteratorVariable1 = new T[count];
            foreach (T iteratorVariable2 in enumeration)
            {
                iteratorVariable1[iteratorVariable0++] = iteratorVariable2;
                if (iteratorVariable0 == count)
                {
                    yield return iteratorVariable1;
                    iteratorVariable0 = 0;
                    iteratorVariable1 = new T[count];
                }
            }
            if (iteratorVariable0 != 0)
            {
                yield return iteratorVariable1;
            }
        }

        public static int IndexOf<T>(this IEnumerable<T> enumeration, T value) where T: IEquatable<T>
        {
            return enumeration.IndexOf<T>(value, EqualityComparer<T>.Default);
        }

        public static int IndexOf<T>(this IEnumerable<T> enumeration, T value, IEqualityComparer<T> comparer)
        {
            int num = 0;
            foreach (T local in enumeration)
            {
                if (comparer.Equals(local, value))
                {
                    return num;
                }
                num++;
            }
            return -1;
        }

        public static int IndexOf<T>(this IEnumerable<T> enumeration, T value, int startIndex) where T: IEquatable<T>
        {
            return enumeration.IndexOf<T>(value, startIndex, EqualityComparer<T>.Default);
        }

        public static int IndexOf<T>(this IEnumerable<T> enumeration, T value, int startIndex, IEqualityComparer<T> comparer)
        {
            for (int i = startIndex; i < enumeration.Count<T>(); i++)
            {
                T x = enumeration.ElementAt<T>(i);
                if (comparer.Equals(x, value))
                {
                    return i;
                }
            }
            return -1;
        }

        public static int IndexOfPrevious<T>(this IEnumerable<T> items, T value, int fromIndex)
        {
            for (int i = fromIndex - 1; i > -1; i--)
            {
                T x = items.ElementAt<T>(i);
                if (EqualityComparer<T>.Default.Equals(x, value))
                {
                    return i;
                }
            }
            return -1;
        }

        public static bool IsNullEmpty(this IEnumerable source)
        {
            if (!source.IsNull())
            {
                IEnumerator enumerator = source.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        object current = enumerator.Current;
                        return false;
                    }
            }
            return true;
        }

        public static string Join<T>(this IEnumerable<T> target, string separator)
        {
            StringBuilder builder = new StringBuilder();
            foreach (T local in target)
            {
                builder.AppendFormat("{0}{1}", local.ToString(), separator);
            }
            return builder.ToString().Left((builder.Length - separator.Length));
        }

        public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int size)
        {
            int iteratorVariable0 = 1;
            IEnumerable<T> iteratorVariable1 = source.Take<T>(size).AsEnumerable<T>();
            while (true)
            {
                if (!iteratorVariable1.Any<T>())
                {
                    yield break;
                }
                yield return iteratorVariable1;
                iteratorVariable1 = source.Skip<T>((iteratorVariable0++ * size)).Take<T>(size).AsEnumerable<T>();
            }
        }

        public static IEnumerable<T> Rand<T>(this IEnumerable<T> list)
        {
            return (from p in list
                orderby Guid.NewGuid()
                select p);
        }

        public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int? start)
        {
            return source.Slice<T>(start, null, null);
        }

        public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int? start, int? stop)
        {
            return source.Slice<T>(start, stop, null);
        }

        public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int? start, int? stop, int? step)
        {
            if (source.IsNull())
            {
                throw new ArgumentNullException("source");
            }
            if (step == 0)
            {
                throw new ArgumentException("step不能为0", "step");
            }
            IList<T> iteratorVariable0 = source as IList<T>;
            if (iteratorVariable0.IsNull())
            {
                iteratorVariable0 = new List<T>(source);
            }
            if (iteratorVariable0.Count != 0)
            {
                int iteratorVariable1 = step.HasValue ? step.GetValueOrDefault() : 1;
                int iteratorVariable2 = start.HasValue ? start.GetValueOrDefault() : ((iteratorVariable1 > 0) ? 0 : (iteratorVariable0.Count - 1));
                int iteratorVariable3 = stop.HasValue ? stop.GetValueOrDefault() : ((iteratorVariable1 > 0) ? iteratorVariable0.Count : -1);
                if (start < 0)
                {
                    iteratorVariable2 = iteratorVariable0.Count + iteratorVariable2;
                }
                if (stop < 0)
                {
                    iteratorVariable3 = iteratorVariable0.Count + iteratorVariable3;
                }
                iteratorVariable2 = Math.Max(iteratorVariable2, (iteratorVariable1 > 0) ? 0 : -2147483648);
                iteratorVariable2 = Math.Min(iteratorVariable2, (iteratorVariable1 > 0) ? iteratorVariable0.Count : (iteratorVariable0.Count - 1));
                iteratorVariable3 = Math.Max(iteratorVariable3, -1);
                iteratorVariable3 = Math.Min(iteratorVariable3, iteratorVariable0.Count);
                for (int i = iteratorVariable2; (iteratorVariable1 > 0) ? (i < iteratorVariable3) : (i > iteratorVariable3); i += iteratorVariable1)
                {
                    yield return iteratorVariable0[i];
                }
            }
        }

        public static string ToCSV<T>(this IEnumerable<T> collection, string delim)
        {
            if (collection.IsNull())
            {
                return string.Empty;
            }
            StringBuilder builder = new StringBuilder();
            foreach (T local in collection)
            {
                builder.Append(local);
                builder.Append(delim);
            }
            if (builder.Length > 0)
            {
                builder.Length -= delim.Length;
            }
            return builder.ToString();
        }

        public static DataTable ToDataTable<T>(this IEnumerable<T> varlist)
        {
            DataTable table = new DataTable();
            PropertyInfo[] properties = null;
            if (!varlist.IsNull())
            {
                foreach (T local in varlist)
                {
                    if (properties.IsNull())
                    {
                        properties = local.GetType().GetProperties();
                        foreach (PropertyInfo info in properties)
                        {
                            Type propertyType = info.PropertyType;
                            if (propertyType.IsGenericType && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                            {
                                propertyType = propertyType.GetGenericArguments()[0];
                            }
                            table.Columns.Add(new DataColumn(info.Name, propertyType));
                        }
                    }
                    DataRow row = table.NewRow();
                    foreach (PropertyInfo info2 in properties)
                    {
                        row[info2.Name] = info2.GetValue(local, null).IsNull() ? DBNull.Value : info2.GetValue(local, null);
                    }
                    table.Rows.Add(row);
                }
            }
            return table;
        }

        public static DataTable ToDataTable2<T>(this IEnumerable<T> enumerable)
        {
            DataTable table = new DataTable();
            IEnumerable<PropertyInfo> properties = typeof(T).GetProperties();
            if ((properties.IsNull() || (properties.Count<PropertyInfo>() == 0)) || (typeof(T) == typeof(string)))
            {
                table.Columns.Add(new DataColumn("Value", typeof(string)));
                foreach (T local in enumerable)
                {
                    DataRow row = table.NewRow();
                    row["Value"] = local.ToString();
                    table.Rows.Add(row);
                }
                return table;
            }
            foreach (PropertyInfo info in properties)
            {
                table.Columns.Add(new DataColumn(info.Name, info.PropertyType));
            }
            foreach (T local2 in enumerable)
            {
                DataRow row2 = table.NewRow();
                foreach (PropertyInfo info2 in properties)
                {
                    row2[info2.Name] = info2.GetValue(local2, null);
                }
                table.Rows.Add(row2);
            }
            return table;
        }

        public static HashSet<TDestination> ToHashSet<TDestination>(this IEnumerable<TDestination> source)
        {
            return new HashSet<TDestination>(source);
        }

        public static string ToJson<TSource, TResult>(this IEnumerable<TSource> varlist, Func<TSource, TResult> selector)
        {
            return varlist.Select<TSource, TResult>(selector).ToJson();
        }

        public static List<TSource> ToPage<TSource>(this IEnumerable<TSource> varlist, int pageIndex, int pageSize, out int totalRecords)
        {
            totalRecords = varlist.Count<TSource>();
            return varlist.Skip<TSource>(((pageIndex - 1) * pageSize)).Take<TSource>(pageSize).ToList<TSource>();
        }

        public static Queue<T> ToQueue<T>(this IEnumerable<T> enumerable)
        {
            Queue<T> queue = new Queue<T>();
            foreach (T local in enumerable)
            {
                queue.Enqueue(local);
            }
            return queue;
        }

        public static ReadOnlyCollection<TDestination> ToReadOnlyCollection<TDestination>(this IEnumerable source)
        {
            List<TDestination> list = new List<TDestination>();
            if (source.IsNotNull())
            {
                foreach (TDestination local in source)
                {
                    list.Add(local);
                }
            }
            return new ReadOnlyCollection<TDestination>(list);
        }

        public static Stack<T> ToStack<T>(this IEnumerable<T> enumerable)
        {
            Stack<T> stack = new Stack<T>();
            foreach (T local in enumerable.Reverse<T>())
            {
                stack.Push(local);
            }
            return stack;
        }
    }
}

